/*
 *  Array.h
 *  NSE_SOLVER
 *
 *  Created by Patrick Zulian on 1/14/11.
 *  Copyright 2011 ICS - USI - Lugano. All rights reserved.
 *
 */

#ifndef NSE_SOLVER_ARRAY_H
#define NSE_SOLVER_ARRAY_H

#include "Base.h"
#include "Utils.h"

namespace nsesolver {
	
	
	template< typename T >
	class Array {
	private:
		
		int size_;
		T * data;
		
		
	public:
		typedef T Type;
		
		
		explicit Array(int size_ /* = 1 */)
		: size_(size_), data(new T[size_])
		{
			NSE_SOLVER_ASSERT( size() > 0 );
		}
		
		explicit Array(int size_, const T array[])
		: size_(size_), data(new T[size_])
		{
			utils::Copy< T > (data, array, size_);
		}
		
		virtual
		~Array()
		{
			delete[] data;
			
		}
		
		Array(const Array &other)
		: size_(other.size()), data(new T[other.size()])
		{
			utils::Copy< T >(data, other.data, size());
		}
		
		
		Array & operator = (const Array &other)
		{
			if (this == &other) {
				return *this;
			}
			
			if (size() != other.size()) {
				delete[] data;
				size_ = other.size();
				data = new T[size()];
			}
			
			
			utils::Copy< T >(data, other.data, size());
			return *this;
			
		}
		
		inline
		Array & swap(Array &other)
		{
			if (this == &other) {
				return *this;
			}
			
			int tempSize = other.size();
			T * tempData = other.data;
			
			other.size_ = size_;
			other.data = data;
			
			size_ = tempSize;
			data = tempData;
			
			return *this;
		}
		
		//STL overload 
		friend 
		inline void swap(Array &a1, Array &a2)
		{
			a1.swap(a2);
		}
		
		
		
		inline
		T & operator[](int index)
		{
			NSE_SOLVER_ASSERT( index < size() );
			NSE_SOLVER_ASSERT( index >= 0 );
			
			return data[index];
		}
		
		inline
		const T & operator[](int index) const
		{
			NSE_SOLVER_ASSERT( index < size() );
			NSE_SOLVER_ASSERT( index >= 0 );
			
			return data[index];
		}
		
		inline
		int size() const
		{
			return size_;
		}
		
		inline
		void resize(int newSize, bool keepContent = true)
		{
			if (this->size() == newSize) {
				return;
			}
			
			T * tempData = data;
			data = new T[newSize];
			
			if (keepContent) {
				utils::Copy(data, tempData, size());
			}

			this->size_ = newSize;
			delete[] tempData;
			
		}
		
			
		inline
		Array & allSet(const T &value)
		{
			utils::InitArray(data, value, size());
			return *this;
		}
			
		
		
		//Output
		friend
		std::ostream & operator <<(std::ostream &os, const Array &array)
		{
			for (int i = 0; i < array.size(); i++) {
				os << array[i];
				if (i < array.size() -1) {
					os << " ";
				}
			}
			
			os << std::endl;
			return os;
		}
		
	};
	
}

#endif

